package rht

import (
	"fmt"
	"strings"
	"sync"
	"time"
)

type Store interface {
	Set(key string, value any)
	SetString(key string, value string)
	SetInt(key string, value int)
	SetInt8(key string, value int8)
	SetInt16(key string, value int16)
	SetInt32(key string, value int32)
	SetInt64(key string, value int64)
	SetUint(key string, value uint)
	SetUint8(key string, value uint8)
	SetUint16(key string, value uint16)
	SetUint32(key string, value uint32)
	SetUint64(key string, value uint64)
	SetBool(key string, value bool)
	SetFloat32(key string, value float32)
	SetFloat64(key string, value float64)
	SetTime(key string, value time.Time)
	SetTimeUnix(key string, value time.Time)
	SetTimeUnixMilli(key string, value time.Time)

	Get(key string) any
	GetValue(key string) (any, bool)
	GetString(key string, def ...string) string
	GetInt(key string, def ...int) int
	GetInt8(key string, def ...int8) int8
	GetInt16(key string, def ...int16) int16
	GetInt32(key string, def ...int32) int32
	GetInt64(key string, def ...int64) int64
	GetUint(key string, def ...uint) uint
	GetUint8(key string, def ...uint8) uint8
	GetUint16(key string, def ...uint16) uint16
	GetUint32(key string, def ...uint32) uint32
	GetUint64(key string, def ...uint64) uint64
	GetBool(key string, def ...bool) bool
	GetFloat32(key string, def ...float32) float32
	GetFloat64(key string, def ...float64) float64
	GetTime(key string, def ...time.Time) time.Time
	GetTimeUnix(key string, def ...time.Time) int64
	GetTimeUnixMilli(key string, def ...time.Time) int64

	Exist(key string) bool
	Delete(key string)
	Clear()
}

var _ Store = new(_Store)

func newStore() Store {
	return &_Store{
		rwl:  sync.RWMutex{},
		data: make(map[string]any),
	}
}

type _Store struct {
	rwl  sync.RWMutex
	data map[string]any
}

func (s *_Store) Set(key string, value any) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetString(key string, value string) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetInt(key string, value int) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetInt8(key string, value int8) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetInt16(key string, value int16) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetInt32(key string, value int32) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetInt64(key string, value int64) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetUint(key string, value uint) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetUint8(key string, value uint8) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetUint16(key string, value uint16) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetUint32(key string, value uint32) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetUint64(key string, value uint64) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetBool(key string, value bool) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetFloat32(key string, value float32) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetFloat64(key string, value float64) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetTime(key string, value time.Time) {
	s.rwl.Lock()
	s.data[key] = value
	s.rwl.Unlock()
}

func (s *_Store) SetTimeUnix(key string, value time.Time) {
	s.rwl.Lock()
	s.data[key] = value.Unix()
	s.rwl.Unlock()
}

func (s *_Store) SetTimeUnixMilli(key string, value time.Time) {
	s.rwl.Lock()
	s.data[key] = value.UnixMilli()
	s.rwl.Unlock()
}

func (s *_Store) Get(key string) any {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		return v
	}
	return nil
}

func (s *_Store) GetValue(key string) (any, bool) {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	v, ok := s.data[key]
	return v, ok
}

func (s *_Store) GetString(key string, def ...string) string {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		if v2, ok2 := v.(string); ok2 {
			return v2
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return ""
}

func (s *_Store) GetInt(key string, def ...int) int {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		switch v.(type) {
		case uint:
			return int(v.(uint))
		case uint8:
			return int(v.(uint8))
		case uint16:
			return int(v.(uint16))
		case uint32:
			return int(v.(uint32))
		case uint64:
			return int(v.(uint64))
		case int:
			return v.(int)
		case int8:
			return int(v.(int8))
		case int16:
			return int(v.(int16))
		case int32:
			return int(v.(int32))
		case int64:
			return int(v.(int64))
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0
}

func (s *_Store) GetInt8(key string, def ...int8) int8 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		switch v.(type) {
		case uint:
			return int8(v.(uint))
		case uint8:
			return int8(v.(uint8))
		case uint16:
			return int8(v.(uint16))
		case uint32:
			return int8(v.(uint32))
		case uint64:
			return int8(v.(uint64))
		case int:
			return int8(v.(int))
		case int8:
			return v.(int8)
		case int16:
			return int8(v.(int16))
		case int32:
			return int8(v.(int32))
		case int64:
			return int8(v.(int64))
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0
}
func (s *_Store) GetInt16(key string, def ...int16) int16 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		switch v.(type) {
		case uint:
			return int16(v.(uint))
		case uint8:
			return int16(v.(uint8))
		case uint16:
			return int16(v.(uint16))
		case uint32:
			return int16(v.(uint32))
		case uint64:
			return int16(v.(uint64))
		case int:
			return int16(v.(int))
		case int8:
			return int16(v.(int8))
		case int16:
			return v.(int16)
		case int32:
			return int16(v.(int32))
		case int64:
			return int16(v.(int64))
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0
}
func (s *_Store) GetInt32(key string, def ...int32) int32 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		switch v.(type) {
		case uint:
			return int32(v.(uint))
		case uint8:
			return int32(v.(uint8))
		case uint16:
			return int32(v.(uint16))
		case uint32:
			return int32(v.(uint32))
		case uint64:
			return int32(v.(uint64))
		case int:
			return int32(v.(int))
		case int8:
			return int32(v.(int8))
		case int16:
			return int32(v.(int16))
		case int32:
			return v.(int32)
		case int64:
			return int32(v.(int64))
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0
}
func (s *_Store) GetInt64(key string, def ...int64) int64 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		switch v.(type) {
		case uint:
			return int64(v.(uint))
		case uint8:
			return int64(v.(uint8))
		case uint16:
			return int64(v.(uint16))
		case uint32:
			return int64(v.(uint32))
		case uint64:
			return int64(v.(uint64))
		case int:
			return int64(v.(int))
		case int8:
			return int64(v.(int8))
		case int16:
			return int64(v.(int16))
		case int32:
			return int64(v.(int32))
		case int64:
			return v.(int64)
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0
}

func (s *_Store) GetUint(key string, def ...uint) uint {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		switch v.(type) {
		case uint:
			return v.(uint)
		case uint8:
			return uint(v.(uint8))
		case uint16:
			return uint(v.(uint16))
		case uint32:
			return uint(v.(uint32))
		case uint64:
			return uint(v.(uint64))
		case int:
			return uint(v.(int))
		case int8:
			return uint(v.(int8))
		case int16:
			return uint(v.(int16))
		case int32:
			return uint(v.(int32))
		case int64:
			return uint(v.(int64))
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0
}

func (s *_Store) GetUint8(key string, def ...uint8) uint8 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		switch v.(type) {
		case uint:
			return uint8(v.(uint))
		case uint8:
			return v.(uint8)
		case uint16:
			return uint8(v.(uint16))
		case uint32:
			return uint8(v.(uint32))
		case uint64:
			return uint8(v.(uint64))
		case int:
			return uint8(v.(int))
		case int8:
			return uint8(v.(int8))
		case int16:
			return uint8(v.(int16))
		case int32:
			return uint8(v.(int32))
		case int64:
			return uint8(v.(int64))
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0
}
func (s *_Store) GetUint16(key string, def ...uint16) uint16 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		switch v.(type) {
		case uint:
			return uint16(v.(uint))
		case uint8:
			return uint16(v.(uint8))
		case uint16:
			return v.(uint16)
		case uint32:
			return uint16(v.(uint32))
		case uint64:
			return uint16(v.(uint64))
		case int:
			return uint16(v.(int))
		case int8:
			return uint16(v.(int8))
		case int16:
			return uint16(v.(int16))
		case int32:
			return uint16(v.(int32))
		case int64:
			return uint16(v.(int64))
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0
}
func (s *_Store) GetUint32(key string, def ...uint32) uint32 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		switch v.(type) {
		case uint:
			return uint32(v.(uint))
		case uint8:
			return uint32(v.(uint8))
		case uint16:
			return uint32(v.(uint16))
		case uint32:
			return v.(uint32)
		case uint64:
			return uint32(v.(uint64))
		case int:
			return uint32(v.(int))
		case int8:
			return uint32(v.(int8))
		case int16:
			return uint32(v.(int16))
		case int32:
			return uint32(v.(int32))
		case int64:
			return uint32(v.(int64))
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0
}
func (s *_Store) GetUint64(key string, def ...uint64) uint64 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		switch v.(type) {
		case uint:
			return uint64(v.(uint))
		case uint8:
			return uint64(v.(uint8))
		case uint16:
			return uint64(v.(uint16))
		case uint32:
			return uint64(v.(uint32))
		case uint64:
			return v.(uint64)
		case int:
			return uint64(v.(int))
		case int8:
			return uint64(v.(int8))
		case int16:
			return uint64(v.(int16))
		case int32:
			return uint64(v.(int32))
		case int64:
			return uint64(v.(int64))
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0
}

func (s *_Store) GetBool(key string, def ...bool) bool {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		if v2, ok2 := v.(bool); ok2 {
			return v2
		} else {
			switch strings.ToLower(fmt.Sprint(v)) {
			case "false":
				return false
			case "true":
				return true
			case "f":
				return false
			case "t":
				return true
			case "0":
				return false
			case "1":
				return true
			}
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return false
}

func (s *_Store) GetFloat32(key string, def ...float32) float32 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		if v2, ok2 := v.(float32); ok2 {
			return v2
		} else if v3, ok3 := v.(float64); ok3 {
			return float32(v3)
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0.0
}

func (s *_Store) GetFloat64(key string, def ...float64) float64 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		if v2, ok2 := v.(float64); ok2 {
			return v2
		} else if v3, ok3 := v.(float32); ok3 {
			return float64(v3)
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return 0.0
}

func (s *_Store) GetTime(key string, def ...time.Time) time.Time {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		if v2, ok2 := v.(time.Time); ok2 {
			return v2
		}
	}
	if len(def) == 1 {
		return def[0]
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))]
	}
	return time.Time{}
}

func (s *_Store) GetTimeUnix(key string, def ...time.Time) int64 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		if v2, ok2 := v.(time.Time); ok2 {
			return v2.Unix()
		}
	}
	if len(def) == 1 {
		return def[0].Unix()
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))].Unix()
	}
	return 0
}

func (s *_Store) GetTimeUnixMilli(key string, def ...time.Time) int64 {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	if v, ok := s.data[key]; ok {
		if v2, ok2 := v.(time.Time); ok2 {
			return v2.UnixMilli()
		}
	}
	if len(def) == 1 {
		return def[0].UnixMilli()
	} else if len(def) > 1 {
		return def[_Rand.IntN(len(def))].UnixMilli()
	}
	return 0
}

func (s *_Store) Exist(key string) bool {
	s.rwl.RLock()
	defer s.rwl.RUnlock()
	_, ok := s.data[key]
	return ok
}

func (s *_Store) Delete(key string) {
	s.rwl.Lock()
	defer s.rwl.Unlock()
	delete(s.data, key)
}

func (s *_Store) Clear() {
	s.rwl.Lock()
	defer s.rwl.Unlock()
	clear(s.data)
}
